package com.quick.develop.flowable.listener;

import com.quick.develop.framework.utils.collection.CollectionUtils;
import com.quick.develop.flowable.application.IBpmRuleApplication;
import com.quick.develop.flowable.application.IBpmTaskAssigneeApplication;
import com.quick.develop.flowable.domain.rule.BpmProcessRule;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.CallActivity;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

import static com.quick.develop.framework.utils.collection.CollectionUtils.convertSet;

/**
 * @author junyuan.liu
 * @description:  多实例节点执行监听 分配人员
 * @date 2022/5/27 14:45
 */
@Slf4j
@Component(value = "multiInstanceExecutionListener")
public class MultiInstanceExecutionListener implements ExecutionListener {
    private static final long serialVersionUID = -5682328570415598327L;
    
    @Autowired
    private IBpmRuleApplication bpmRuleApplication;
    
    @Autowired
    private IBpmTaskAssigneeApplication bpmTaskAssigneeApplication;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void notify(DelegateExecution delegateExecution) {
        if (delegateExecution.getParent().isMultiInstanceRoot()){
            log.info("多实例后续进入不设置参数，直接return");
            return;
        }
        log.info("多实例首次进入设置参数");
        
        String activityId = delegateExecution.getCurrentActivityId();
        String processInstanceId = delegateExecution.getProcessInstanceId();
        FlowElement currentFlowElement = delegateExecution.getCurrentFlowElement();
        MultiInstanceLoopCharacteristics loopCharacteristics = null;
        if (currentFlowElement instanceof UserTask ){
            loopCharacteristics = ((UserTask) currentFlowElement).getLoopCharacteristics();
        }else if (currentFlowElement instanceof CallActivity) {
            loopCharacteristics = ((CallActivity) currentFlowElement).getLoopCharacteristics();
        }
        
        //如果是多实例
        if ( Objects.nonNull(loopCharacteristics )) {
            //模型ID
            String modelKey = currentFlowElement.getParentContainer().getId();
            String assigneeKey = loopCharacteristics.getInputDataItem();
            BpmProcessRule rule = bpmRuleApplication.getTaskRule(modelKey, activityId);
            Set<String> candidateUsers = bpmTaskAssigneeApplication.calculateTaskCandidateUsers(processInstanceId, rule,delegateExecution);
            
            if (Objects.isNull(delegateExecution.getVariable(assigneeKey)) ){
                delegateExecution.setVariable(assigneeKey, candidateUsers);
            }else {
                Set<String> assignees = getAssignees(assigneeKey, candidateUsers, delegateExecution);
                if (!assignees.isEmpty()){
                    delegateExecution.setVariable(assigneeKey, assignees);
                }
            }
        }
    }
    private Set<String> getAssignees(String assigneeKey, Set<String> candidateUsers, DelegateExecution delegateExecution){
        Set<String> users = new HashSet<>();
        Set<String> oldUsers = new HashSet<>();
        if (delegateExecution.getVariable(assigneeKey) instanceof Collection){
            Collection<?> assigneeList = (Collection<?>) delegateExecution.getVariable(assigneeKey);
            oldUsers = convertSet(assigneeList, String::valueOf);
        }
        if (!CollectionUtils.equalsSet(candidateUsers, oldUsers)){
            users = candidateUsers;
        }
        return users;
        
    }
    
}
